<template>
  <div style="width: 100%; height: 98%;">
    <div style="border-bottom: 1px solid #ebeef5;">
      <el-button-group style="margin-top: 2px; margin-left: 2px; margin-bottom: 2px;">
        <el-tooltip v-permission="'/manage/route/add'" content="新建根菜单" placement="top" :open-delay="500">
          <el-button type="primary" icon="el-icon-folder-add" size="mini" @click="handleCreateRoute(0)" />
        </el-tooltip>
      </el-button-group>
    </div>
    <div id="leftDiv" style="overflow-y: scroll; height: 90vh;">
      <el-tree
        ref="tree"
        :data="treeData"
        :props="props"
        :expand-on-click-node="false"
        @current-change="handleTreeNodeChange"
      >
        <span slot-scope="{ node, data }" class="custom-tree-node">
          <span>
            <i v-if="data.isRoute" class="el-icon-menu" style="color: #67C23A;" />
            <i v-else class="el-icon-cpu" />
            {{ node.label }}
          </span>
          <span v-if="data.isRoute">
            <el-tooltip v-if="!data.hidden" content="显示（hidden=false）" placement="top" :open-delay="500">
              <svg-icon icon-class="eye-open" />
            </el-tooltip>
            <el-tooltip v-else content="隐藏（hidden=true）" placement="top" :open-delay="500">
              <svg-icon icon-class="eye" />
            </el-tooltip>
            <el-tooltip v-permission="'/manage/route/add'" content="当需要在左侧菜单栏中增加子菜单时，需要新建菜单" placement="top" :open-delay="500">
              <el-button style="margin-left: 10px;" type="text" size="mini" @click="handleCreateRoute(data.id)">新建菜单</el-button>
            </el-tooltip>
            <el-tooltip v-permission="'/manage/route/add'" content="当页面上需要根据权限显示或隐藏某些功能时，需要新建指令" placement="top" :open-delay="500">
              <el-button type="text" size="mini" @click="handleCreateDirective(data.id)">新建指令</el-button>
            </el-tooltip>
            <el-button v-permission="'/manage/route/update'" type="text" size="mini" @click="handleUpdateRoute(data.id)">修改</el-button>
            <el-button v-permission="'/manage/route/delete'" type="text" size="mini" @click="delRoute(node, data.id)">删除</el-button>
          </span>
          <span v-else>
            <el-button v-permission="'/manage/route/delete'" type="text" size="mini" @click="delRoute(node, data.id)">删除</el-button>
          </span>
        </span>
      </el-tree>
    </div>

    <!-- 新建菜单 -->
    <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" width="700px" :close-on-click-modal="false">
      <el-form ref="dataForm" :rules="rules" :model="temp" label-position="left" label-width="100px">
        <el-form-item label="路径" prop="path">
          <el-input v-model="temp.path" placeholder="path 属性: 路由匹配的路径（根节点前要加 /）" />
        </el-form-item>
        <el-form-item label="名称" prop="name">
          <el-input v-model="temp.name" placeholder="name 属性: 路由名称" />
        </el-form-item>
        <el-form-item label="组件名称" prop="component">
          <el-input v-model="temp.component" placeholder="component 属性: 对应加载的组件名称（根节点要输入 layout）。" />
        </el-form-item>
        <el-form-item label="重定向路径">
          <el-input v-model="temp.redirect" placeholder="redirect 属性: 重定向的路由路径" />
        </el-form-item>
        <el-form-item label="标题" prop="meta.title">
          <el-input v-model="temp.meta.title" placeholder="title 属性: 页面标题" />
        </el-form-item>
        <el-form-item label="图标">
          <el-input v-model="temp.meta.icon" placeholder="icon 属性: 图标" />
        </el-form-item>
        <el-form-item label="高亮菜单">
          <el-input v-model="temp.meta.activeMenu" placeholder="activeMenu 属性: 当勾选隐藏后，需要高亮显示的侧边栏菜单的路由路径" />
        </el-form-item>
        <el-form-item label="props">
          <el-input v-model="temp.props" placeholder="props 属性: 需要向页面传递数据的 props 属性" />
        </el-form-item>
        <el-form-item label="">
          <el-tooltip content="hidden 属性: 在菜单中隐藏" placement="top" :open-delay="500">
            <el-checkbox v-model="temp.hidden">隐藏</el-checkbox>
          </el-tooltip>
          <el-tooltip content="alwaysShow 属性: 始终显示根菜单" placement="top" :open-delay="500">
            <el-checkbox v-model="temp.alwaysShow">总是显示</el-checkbox>
          </el-tooltip>
          <el-tooltip content="noCache 属性: 禁用缓存页面" placement="top" :open-delay="500">
            <el-checkbox v-model="temp.meta.noCache">禁用缓存</el-checkbox>
          </el-tooltip>
          <el-tooltip content="affix 属性: 在 tags-view 中是否可关闭" placement="top" :open-delay="500">
            <el-checkbox v-model="temp.meta.affix">不可关闭</el-checkbox>
          </el-tooltip>
          <el-tooltip content="breadcrumb 属性: 是否显示面包屑" placement="top" :open-delay="500">
            <el-checkbox v-model="temp.meta.breadcrumb">面包屑</el-checkbox>
          </el-tooltip>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取消</el-button>
        <el-button type="primary" @click="dialogStatus==='create'?createRoute():updateRoute()">确定</el-button>
      </div>
    </el-dialog>

    <!-- 新建指令 -->
    <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogDirectiveFormVisible" width="700px" :close-on-click-modal="false">
      <el-form ref="dataDirectiveForm" :rules="rules" :model="temp" label-position="left" label-width="100px">
        <el-form-item label="指令资源" prop="resourceId">
          <el-select v-model="temp.resourceId" style="width:80%" filterable placeholder="请选择 指令资源">
            <el-option
              v-for="item in resourceList"
              :key="item.id"
              :label="item.desc"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogDirectiveFormVisible = false">取消</el-button>
        <el-button type="primary" @click="createDirective()">确定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<style>
.el-tree-node.is-current > .el-tree-node__content { /* 修改选中当前节点的样式 */
  background-color: rgba(135, 206, 235, 0.3);
}
</style>
<style>
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
</style>

<style>
#leftDiv::-webkit-scrollbar, #rightDiv::-webkit-scrollbar {
  width: 0px;
}
</style>

<script>
import { listTree, selectById as selectRouteById, add as addRoute, update as updateRoute, del as deleteRoute } from '@/api/manage/route'
import { listAll as listAllResource } from '@/api/manage/resource'

export default {
  filters: {
    statusFilter(status) {
      const statusMap = {
        published: 'success',
        draft: 'gray',
        deleted: 'danger'
      }
      return statusMap[status]
    }
  },
  data() {
    return {
      dialogFormVisible: false,
      dialogDirectiveFormVisible: false,
      dialogStatus: '',
      textMap: {
        update: '修改',
        create: '添加'
      },
      props: { // tree 的 props 对象，用来映射新的 tree 属性
        label: 'name',
        children: 'children',
        isLeaf: 'leaf',
        key: 'id'
      },
      treeData: [], // tree 数据
      resourceList: [], // resource 列表
      temp: { },
      rules: {
        path: [
          { required: true, message: '路径 不能为空', trigger: 'blur' },
          { max: 100, message: '路径 长度不能超过 100 个字符', trigger: 'blur' }
        ],
        name: [
          { required: true, message: '名称 不能为空', trigger: 'blur' },
          { max: 100, message: '名称 长度不能超过 100 个字符', trigger: 'blur' }
        ],
        component: [
          { required: true, message: '组件名称 不能为空', trigger: 'blur' },
          { max: 100, message: '组件名称 长度不能超过 100 个字符', trigger: 'blur' }
        ],
        'meta.title': [
          { required: true, message: '标题 不能为空', trigger: 'blur' },
          { max: 100, message: '标题 长度不能超过 100 个字符', trigger: 'blur' }
        ],
        resourceId: [
          { required: true, message: '指令资源 不能为空', trigger: 'blur' }
        ]
      }
    }
  },
  created() {
    this.resetTemp()
    this.loadTreeData()
  },
  methods: {
    // 新增时初始化 temp 数据
    resetTemp() {
      this.temp = {
        id: undefined,
        type: undefined,
        parentId: 0,
        path: '',
        name: '',
        component: '',
        redirect: '',
        props: '',
        hidden: false,
        alwaysShow: false,
        routeMetaId: undefined,
        resourceId: undefined,
        meta: {
          id: undefined,
          title: '',
          icon: '',
          activeMenu: '',
          noCache: false,
          affix: false,
          breadcrumb: true
        }
      }
    },
    // tree：装载 tree 数据
    loadTreeData(parentId, resolve) {
      listTree().then(response => {
        this.treeData = response.data
      })
    },
    // 当 tree 节点选中改变后触发此方法
    handleTreeNodeChange(data, node) {
      if (this.addNewNode) {
        this.addNewNode = false // 如果是添加节点，设置为 false（不是新增节点）
      } else { // 如果不是新增节点，则显示 控件 或 目录 信息
        // 由于点击 tree 节点后边的添加按钮时也会触发 change 事件，所以点击添加按钮不需要改当前节点信息，只有点击一个用例的时候才会改变当前节点信息
        this.currentNodeData = data
        this.currentNode = node
      }
    },
    /**
     * 添加节点
     * @param id 数据库中的 id
     * @param parentId 父分类 id，0 为根节点
     * @param name tree 中显示的 label
     * @param isRoute 是否是路由
     */
    appendNode(id, parentId, name, isRoute) {
      const newChild = { id: id, name: name, children: [], parentId: parentId, isRoute: JSON.parse(isRoute) }
      if (parentId === 0) {
        this.treeData.push(newChild)
      } else {
        this.$refs.tree.append(newChild, this.currentNode) // 这里每次加一个子节点，如果需要多个可以写多个
      }
      this.currentNodeData = newChild
    },
    /**
     * 改变当前选中节点的数据
     * @param data
     */
    changeNode(data) {
      if (data instanceof Object) { // 对象，修改 label 和 icon
        if (Object.keys(data).includes('name')) this.currentNodeData.name = data.name
        if (Object.keys(data).includes('hidden')) this.currentNodeData.hidden = data.hidden
      } else { // 字符串，修改 label
        this.currentNodeData.name = data
      }
    },
    handleCreateRoute(parentId) {
      this.resetTemp()
      this.temp.type = 1
      this.temp.parentId = parentId
      if (parentId === 0) {
        this.temp.component = 'layout'
      }
      this.dialogStatus = 'create'
      this.dialogFormVisible = true
      this.$nextTick(() => {
        this.$refs['dataForm'].clearValidate()
      })
    },
    createRoute() {
      this.$refs['dataForm'].validate((valid) => {
        if (valid) {
          addRoute(this.temp).then((response) => {
            this.dialogFormVisible = false
            this.appendNode(response.data.id, response.data.parentId, response.data.meta.title, true)
            this.$message({ message: '添加成功!', type: 'success' })
          })
        }
      })
    },
    handleUpdateRoute(id) {
      selectRouteById(id).then((response) => {
        this.temp = response.data
        this.dialogStatus = 'update'
        this.dialogFormVisible = true
        this.$nextTick(() => {
          this.$refs['dataForm'].clearValidate()
        })
      })
    },
    updateRoute() {
      this.$refs['dataForm'].validate((valid) => {
        if (valid) {
          const tempData = Object.assign({}, this.temp)
          updateRoute(tempData).then((response) => {
            this.dialogFormVisible = false
            this.changeNode({ name: response.data.meta.title, hidden: response.data.hidden })
            this.$message({ message: '修改成功!', type: 'success' })
          })
        }
      })
    },
    handleCreateDirective(parentId) {
      // 查询 资源 列表
      this.resourceList = []
      listAllResource().then((response) => {
        this.resourceList = response.data
      })

      this.resetTemp()
      this.temp.type = 2
      this.temp.parentId = parentId
      this.dialogStatus = 'create'
      this.dialogDirectiveFormVisible = true
      this.$nextTick(() => {
        this.$refs['dataDirectiveForm'].clearValidate()
      })
    },
    createDirective() {
      this.$refs['dataDirectiveForm'].validate((valid) => {
        if (valid) {
          addRoute(this.temp).then((response) => {
            this.dialogDirectiveFormVisible = false
            this.appendNode(response.data.id, response.data.parentId, response.data.name, false)
            this.$message({ message: '添加成功!', type: 'success' })
          })
        }
      })
    },
    delRoute(node, id) {
      this.currentNode = node // 设置当前节点
      this.addNewNode = true
      this.$confirm('是否删除 "' + node.label + '" ?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        deleteRoute(id).then(response => {
          node.remove() // tree 上删除节点
          this.$message({ type: 'success', message: '删除成功!' })
        })
      })
    }
  }
}
</script>
